package com.bocloud.cmp.service.app.resource;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.app.ApplicationDao;
import com.bocloud.cmp.dao.app.OpenshiftClusterDao;
import com.bocloud.cmp.entity.app.resource.OpenshiftCluster;
import com.bocloud.cmp.interfaces.app.resource.DiagramService;
import com.bocloud.cmp.service.utils.OpenshiftUtil;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.RequestUser;
import com.bocloud.soc.dao.intf.AuthDao;
import com.bocloud.soc.dao.intf.RoleDao;
import com.bocloud.soc.dao.intf.UserDao;
import com.bocloud.soc.entity.Authority;
import com.bocloud.soc.entity.Role;
import com.bocloud.soc.entity.User;
import com.bocloud.soc.interfaces.UserService;

import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.Node;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.client.KubernetesClient;
/**
 * 应用饼状图服务层实现类
 * @author Zaney
 * @data:2017年4月4日
 * @describe:
 */
@Component("diagramService")
public class DiagramServiceImpl implements DiagramService {
	private static Logger logger = LoggerFactory.getLogger(DiagramServiceImpl.class);
	@Autowired
	private OpenshiftClusterDao openshiftClusterDao;
	@Autowired
	private ApplicationDao applicationDao;
	@Autowired
	private OpenshiftUtil openshiftUtil;
	@Autowired
	private UserService userService;
	@Autowired
	private UserDao userDao;
	@Autowired
	private AuthDao authDao;
	@Autowired
	private RoleDao roleDao;

	@Override
	public BsmResult getData(RequestUser requestUser) {
		JSONObject object = new JSONObject();
		JSONObject jsonObject = null;
		JSONArray array = null;
		BigDecimal notRequestCpuTotal = new BigDecimal(0);
		BigDecimal notRequestMemoryTotal = new BigDecimal(0);
		BigDecimal requestCpuTotal = new BigDecimal(0);
		BigDecimal requestMemoryTotal = new BigDecimal(0);
		String proxyUrl = null;
		try{
			//1、获取client
			List<OpenshiftCluster> clusters = openshiftClusterDao.list(0, 0, null, null);
			for (OpenshiftCluster openshiftCluster : clusters) {
				proxyUrl = openshiftCluster.getProxyUrl();
				KubernetesClient client = openshiftUtil.getKubernetesClient(proxyUrl);
				//2、获取所有主机上的cpu/memory
				JSONObject NodeMap = getHostCpuAndMemory(client);
				BigDecimal totalCpu = new BigDecimal(NodeMap.getString("totalCpu"));
				BigDecimal totalMemory = new BigDecimal(NodeMap.getString("totalMemory"));
				//3、获取所有pod request的cpu/memory
				JSONObject podMap = getPodRequestCpuAndMemory(client);
				BigDecimal podRequestCpu = new BigDecimal(podMap.getString("podRequestCpu"));
				BigDecimal podRequestMemory = new BigDecimal(podMap.getString("podRequestMemory"));
				//4、获取未请求数据
				BigDecimal notRequestCpu = totalCpu.subtract(podRequestCpu);
				BigDecimal notRequestMemory = totalMemory.subtract(podRequestMemory);
				//5、累加数据
				requestCpuTotal = requestCpuTotal.add(podRequestCpu);
				requestMemoryTotal = requestMemoryTotal.add(podRequestMemory);
				notRequestCpuTotal = notRequestCpuTotal.add(notRequestCpu);
				notRequestMemoryTotal = notRequestMemoryTotal.add(notRequestMemory);
			}
			//7、统计应用状态信息
			String deptId = userService.listDept(requestUser.getId());
			// 判断当前用户是否拥有查看“容器平台”的权限，如果有则可以查看所有的镜像
			try {
				User user = userDao.query(requestUser.getId());
				List<Role> roles = roleDao.listByUid(user.getId());
				for (Role role : roles) {
					List<Authority> authorities = authDao.listByRid(role.getId());
					for (Authority authority : authorities) {
						// TODO 和威哥少龙沟通后暂时写死判断“容器平台”权限的id
						if (authority.getId().equals(new Long(132))) {
							deptId = null;
							break;
						}
					}
				}
			} catch (Exception e) {
				logger.error("list software failure:", e);
				return new BsmResult(false, "镜像查询失败！获取登陆用户信息失败！");
			}
			Map<String, Object> countApp = countApp(deptId);
			//6、整理数据格式
			/**
			 * cpu
			 */
			array =  new JSONArray();
			//not request cpu
			jsonObject = new JSONObject();
			JSONObject requestCpu = cpuUtilTool(notRequestCpuTotal);
			jsonObject.put("name", "notRequestCpu");
			jsonObject.put("value", requestCpu.getString("value"));
			jsonObject.put("realValue", requestCpu.getString("realValue"));
			array.add(jsonObject);
			//request  cpu
			jsonObject = new JSONObject();
			JSONObject notRequestCpu = cpuUtilTool(requestCpuTotal);
			jsonObject.put("name", "requestCpu");
			jsonObject.put("value", notRequestCpu.getString("value"));
			jsonObject.put("realValue", notRequestCpu.getString("realValue"));
			array.add(jsonObject);
			object.put("cpu", array);
			/**
			 * memeory
			 */
			array =  new JSONArray();
			//not request memory
			jsonObject = new JSONObject();
			JSONObject notRequest = memoryUtilTool(notRequestMemoryTotal);
			jsonObject.put("name", "notRequestMemory");
			jsonObject.put("value", notRequest.getString("value"));
			jsonObject.put("realValue", notRequest.getString("realValue"));
			array.add(jsonObject);
			//request memory
			jsonObject = new JSONObject();
			JSONObject request = memoryUtilTool(requestMemoryTotal);
			jsonObject.put("name", "requestMemory");
			jsonObject.put("value", request.getString("value"));
			jsonObject.put("realValue", request.getString("realValue"));
			array.add(jsonObject);
			object.put("memory", array);
			/**
			 * app
			 */
			array =  new JSONArray();
			//app not deploy
			jsonObject = new JSONObject();
			jsonObject.put("name", "notDeploy");
			jsonObject.put("value", countApp.get("NOT_DEPLOY"));
			jsonObject.put("realValue", Integer.valueOf(countApp.get("NOT_DEPLOY") == null ? "0":(countApp.get("NOT_DEPLOY").toString())));
			array.add(jsonObject);
			//app run
			jsonObject = new JSONObject();
			jsonObject.put("name", "deploy");
			jsonObject.put("value", countApp.get("DEPLOY"));
			jsonObject.put("realValue", Integer.valueOf(countApp.get("DEPLOY") == null ? "0":(countApp.get("DEPLOY").toString())));
			array.add(jsonObject);
			object.put("app", array);
			
			return new BsmResult(true, object, "获取信息成功");
		}catch(Exception e){
			logger.error("连接服务器["+proxyUrl+"]异常", e);
			return new BsmResult(false, "获取信息失败");
		}
		
	}
	

	@Override
	public BsmResult getResource(String proxyUrl, Map<String, String> requests) {
		String memory = null;
		String cpu = null;
		try {
			//1、获取连接
			KubernetesClient client = openshiftUtil.getKubernetesClient(proxyUrl);
			//2、获取所有主机上的cpu/memory
			JSONObject NodeMap = getHostCpuAndMemory(client);
			BigDecimal totalCpu = new BigDecimal(NodeMap.getString("totalCpu"));
			BigDecimal totalMemory = new BigDecimal(NodeMap.getString("totalMemory"));
			//3、获取所有pod request的cpu/memory
			JSONObject podMap = getPodRequestCpuAndMemory(client);
			BigDecimal podRequestCpu = new BigDecimal(podMap.getString("podRequestCpu"));
			BigDecimal podRequestMemory = new BigDecimal(podMap.getString("podRequestMemory"));
			//4、获取未请求数据
			BigDecimal notRequestCpu = totalCpu.subtract(podRequestCpu);
			BigDecimal notRequestMemory = totalMemory.subtract(podRequestMemory);
			//5、获取请求数据
			for (Map.Entry<String, String> entry : requests.entrySet()) {
				if ("memory".equals(entry.getKey())) {
					memory = entry.getValue();
				} else {
					cpu = entry.getValue();
				}
			}
			//6、将请求数据 换算单位 memory为 Ki  cpu为m
			BigDecimal memoryValue = BigDecimal.valueOf(memoryTool(memory));
			BigDecimal cpuValue = BigDecimal.valueOf(cpuTool(cpu));
			//比较memory
			int memoryCompare = memoryValue.compareTo(notRequestMemory);
			//比较cpu
			int cpuCompare = cpuValue.compareTo(notRequestCpu);
			if (memoryCompare < 0 && cpuCompare < 0 ) {
				return new BsmResult(true, "资源充足");
			} else {
				return new BsmResult(false, "资源不充足");
			}
		} catch (Exception e) {
			logger.error("连接服务器["+proxyUrl+"]异常", e);
			return new BsmResult(false, "获取信息失败");
		}
	}

	/**
	 * 获取主机cpu/memory
	 * @param client
	 * @return
	 */
	public JSONObject getHostCpuAndMemory(KubernetesClient client){
		JSONObject jsonObject = new JSONObject();
		//全部主机上的cpu/memory
		Double totalCpu = 0.00;
		Double totalMemory = 0.00;
		try{
			//2、循环所有主机的cpu/memory
			List<Node> nodes = client.nodes().list().getItems();
			for (Node node : nodes) {
				Map<String, Quantity> allocatable = node.getStatus().getAllocatable();
				String memory = allocatable.get("memory").getAmount();
				String cpu = allocatable.get("cpu").getAmount();
				totalMemory += memoryTool(memory);
				totalCpu += cpuTool(cpu);
			}
			jsonObject.put("totalCpu", totalCpu);
			jsonObject.put("totalMemory", totalMemory);
			return jsonObject;
		}catch(Exception e){
			logger.error("获取数值信息异常", e);
			return null;
		}
	}
	/**
	 * 获取pod Requests cpu/memory
	 * @param client
	 * @return
	 */
	public JSONObject getPodRequestCpuAndMemory(KubernetesClient client){
		JSONObject jsonObject = new JSONObject();
		//全部主机上的cpu/memory
		Double totalPodCpu = 0.00;
		Double totalPodmemory = 0.00;
		try{
			List<Pod> pods = client.pods().inAnyNamespace().list().getItems();
			for (Pod pod : pods) {
				List<Container> containers = pod.getSpec().getContainers();
				for (Container container : containers) {
					Map<String, Quantity> requests = container.getResources().getRequests();
					if(requests != null){
						if(requests.toString().contains("cpu")){
							String cpu = requests.get("cpu").getAmount();
							totalPodCpu += cpuTool(cpu);
						}
						if(requests.toString().contains("memory")){
							String memory = requests.get("memory").getAmount();
							totalPodmemory  += memoryTool(memory);
						}
					}
				}
			}
			jsonObject.put("podRequestCpu", totalPodCpu);
			jsonObject.put("podRequestMemory", totalPodmemory);
			return jsonObject;
		}catch(Exception e){
			logger.error("获取数值信息异常", e);
			return null;
		}
	}
	/**
	 * 统计应用状态
	 * @return
	 */
	public Map<String, Object> countApp(String deptId){
		try {
			
			return  applicationDao.countApp(deptId);
		} catch (Exception e) {
			logger.error("统计应用状态数据异常", e);
			return null;
		}
	}
	
	//*===========================根据不同单位获取数值===============================*//
	
	//cpu计算基准单位m
	public double cpuTool(String object){
		double value = 0.00;
		if(object.contains("m")){
			value = Double.parseDouble(object.split("m")[0]);
		}else {
			value = Double.parseDouble(object)*1000;
		}
		return value;
	}
	//memory计算基本单位 Ki
	public double memoryTool(String object){
		double value = 0.00;
		if (object.contains("Ki")) {
			value = Double.parseDouble(object.split("Ki")[0]);
		} else if (object.contains("K")) {
			value = Double.parseDouble(object.split("K")[0]);
		}else if(object.contains("Mi")){
			value = Double.parseDouble(object.split("Mi")[0]);
			value = unitConversion(value, 1);
		}else if (object.contains("M")) {
			value = Double.parseDouble(object.split("M")[0]);
			value = unitConversion(value, 1);
		}else if (object.contains("Gi")) {
			value = Double.parseDouble(object.split("Gi")[0]);
			value = unitConversion(value, 2);
		}else if (object.contains("G")) {
			value = Double.parseDouble(object.split("G")[0]);
			value = unitConversion(value, 2);
		}else if (object.contains("Ti")) {
			value = Double.parseDouble(object.split("Ti")[0]);
			value = unitConversion(value, 3);
		}else if (object.contains("T")) {
			value = Double.parseDouble(object.split("T")[0]);
			value = unitConversion(value, 3);
		}else if (object.contains("Pi")) {
			value = Double.parseDouble(object.split("Pi")[0]);
			value = unitConversion(value, 4);
		}else if (object.contains("P")) {
			value = Double.parseDouble(object.split("P")[0]);
			value = unitConversion(value, 4);
		}else if (object.contains("Ei")) {
			value = Double.parseDouble(object.split("Ei")[0]);
			value = unitConversion(value, 5);
		}else if (object.contains("E")) {
			value = Double.parseDouble(object.split("E")[0]);
			value = unitConversion(value, 5);
		}else{
			value = Double.parseDouble(object);
			value = value / Math.pow(1024, 1);
		}
		return value;
	}
	
	//缩减长度
	public JSONObject cpuUtilTool(BigDecimal bigDecimal){
		JSONObject object = new JSONObject();
		double doubleValue = bigDecimal.doubleValue();
		object.put("value", doubleValue);
		if (doubleValue < Math.pow(1000, 1)) {
			object.put("realValue", bigDecimal.toPlainString()+" m");
			return object;
		} else {
			bigDecimal = bigDecimal.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
			object.put("realValue", bigDecimal.toPlainString()+" core");
			return object;
		}
	}
	// 缩减长度
	public JSONObject memoryUtilTool(BigDecimal bigDecimal){
		JSONObject object = new JSONObject();
		double doubleValue = bigDecimal.doubleValue();
		object.put("value", doubleValue);
		if ( doubleValue < Math.pow(1024, 1)) {//Ki
			object.put("realValue", bigDecimal.toPlainString()+" Ki");
			return object;
		} else if (doubleValue < Math.pow(1024, 2)) {//Mi
			bigDecimal = bigDecimal.divide(BigDecimal.valueOf(Math.pow(1024, 1)), 2, RoundingMode.HALF_UP);
			object.put("realValue", bigDecimal.toPlainString()+" Mi");
			return object;
		} else if (doubleValue < Math.pow(1024, 3)) {//Gi
			bigDecimal = bigDecimal.divide(BigDecimal.valueOf(Math.pow(1024, 2)), 2, RoundingMode.HALF_UP);
			object.put("realValue", bigDecimal.toPlainString()+" Gi");
			return object;
		} else if (doubleValue < Math.pow(1024, 4)) {//Ti
			bigDecimal = bigDecimal.divide(BigDecimal.valueOf(Math.pow(1024, 3)), 2, RoundingMode.HALF_UP);
			object.put("realValue", bigDecimal.toPlainString()+" Ti");
			return object;
		} else if (doubleValue < Math.pow(1024, 5)) {//Pi
			bigDecimal = bigDecimal.divide(BigDecimal.valueOf(Math.pow(1024, 4)), 2, RoundingMode.HALF_UP);
			object.put("realValue", bigDecimal.toPlainString()+" Pi");
			return object;
		} else {//Ei
			bigDecimal = bigDecimal.divide(BigDecimal.valueOf(Math.pow(1024, 5)), 2, RoundingMode.HALF_UP);
			object.put("realValue", bigDecimal.toPlainString()+" Ei");
			return object;
		}
	}
	//单位换算
	public double unitConversion(double value, int n){
		int metric = 1024;
		for (int i = 0; i < n; i++) {
			value = value * metric ;
		}
		return value;
	}

}
